package conservare.web;

import java.io.InputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;

import org.primefaces.context.RequestContext;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;

import conservare.boleto.service.GeradorBoletoService;
import conservare.constantes.Constante;
import conservare.modelo.banco.CarteiraBoleto;
import conservare.modelo.banco.Conta;
import conservare.modelo.contrato.Contrato;
import conservare.modelo.financeiro.ContaAReceber;
import conservare.modelo.financeiro.Pagamento;
import conservare.modelo.type.Mes;
import conservare.modelo.type.TipoBaixaContaPaga;
import conservare.negocio.BancoRN;
import conservare.negocio.ContaAReceberRN;
import conservare.negocio.ContratoRN;
import conservare.negocio.BoletoEmitidoRN;
import conservare.negocio.PagamentoContaAReceberRN;
import conservare.util.JSFUtil;

@ManagedBean
@ViewScoped
public class ContaAReceberBean implements Serializable {

	private static final long serialVersionUID = -5777158764080489836L;

	private List<Contrato> contratos;
	
	//private ContratoDataModel contratosDataModel;
	private Contrato[] contratosSelecionados;
	//private List<ContaAReceber> contasAReceberCadastradas;
	private List<ContaAReceber> contasPendentesDePagamento;
	private List<ContaAReceber> contasAReceberSelecionadas;
	private List<Contrato> contratosFiltrados;
	
	private List<SelectItem> anosItens;
	private List<SelectItem> mesesItens;
	private Mes mesDeReferenciaSelecionado;
	private Integer anoDeReferenciaSelecionado;
	private Date dataDoVencimentoSelecionado;
	private ContaAReceber contaAReceberSelecionada;
	
	private Pagamento pagamentoContaAReceberSelecionada;
	private PreBoleto preBoleto;
	
	
	public String doConfirmarLancamentoDeContasAReceberSelecionadas(){
		
		if(getContratosSelecionados() == null || getContratosSelecionados().length == 0){
			
			JSFUtil.addInfoMessage("Nenhuma conta foi selecionada !");
			return null;
			
		}else{
			
			for(ContaAReceber contaAReceber : getContasAReceberSelecionadas()){
				doSalvarLancamento(contaAReceber);
			}
			JSFUtil.addInfoMessage("Contas lançadas com sucesso !");
			return "contaareceberlistagem.xhtml";
			
		}
		
	}
	
	private void doSalvarLancamento(ContaAReceber contaAReceber){
		new ContaAReceberRN().salvar(contaAReceber);
	}
	
	
	/*public String doPrepararGeracaoBoleto(){
		 JSFUtil.flashScope().put("conta_areceber_selecionada", getContaAReceberSelecionada());   
		 return "/restrito/boleto/geraboleto?faces-redirect=true";
	}*/
	
	public String doPrepararGeracaoBoleto(){
		
		setPreBoleto(new PreBoleto(getContaAReceberSelecionada()));
		
		// JSFUtil.flashScope().put("conta_areceber_selecionada", getContaAReceberSelecionada());   
		// return "/restrito/boleto/geraboleto?faces-redirect=true";
		return null;
	}
	
	public String doPrepararBaixaManualDeContaAReceber(ContaAReceber contaAReceber){
		
		setContaAReceberSelecionada(contaAReceber);
		setPagamentoContaAReceberSelecionada(new PagamentoContaAReceberRN().getNovo(Pagamento.FORMA_PAGAMENTO.VIA_DINHEIRO, TipoBaixaContaPaga.MANUAL));
		
		return null;
		
	}
	
	
	public void doConfirmarBaixa(ActionEvent actionEvent) {
		
		boolean isOk = true; 
		FacesMessage msg = null;
		
		if(getPagamentoContaAReceberSelecionada().getDataDePagamento() == null){
			msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Entre com a data de pagamento", null);
			isOk = false;
		}else if(getPagamentoContaAReceberSelecionada().getValorPago() == null || getPagamentoContaAReceberSelecionada().getValorPago().doubleValue() == 0.0){
			msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Entre com o valor pago", null);
			isOk = false;
		}else if(getPagamentoContaAReceberSelecionada().getValorPago().doubleValue() < getContaAReceberSelecionada().getValorAPagar().doubleValue()){
			msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "O valor pago tem de ser IGUAL ou MAIOR que o valor devedor", null);
			isOk = false;
		}else{
			new ContaAReceberRN().efetuarBaixa(getContaAReceberSelecionada(), getPagamentoContaAReceberSelecionada());
			setContasPendentesDePagamento(null);//força atualizar a lista
			msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Baixa realizada com sucesso !", null);
		}
		
		FacesContext.getCurrentInstance().addMessage(null, msg); 
		RequestContext context = RequestContext.getCurrentInstance(); 
		context.addCallbackParam("isOk", isOk);  
		
	}
	
	
	public PreBoleto getPreBoleto() {
		return preBoleto;
	}

	public void setPreBoleto(PreBoleto preBoleto) {
		this.preBoleto = preBoleto;
	}

	public List<Contrato> getContratos() {
		if(contratos == null){
			contratos = new ContratoRN().getTodos();
		}
		return contratos;
	}
	
	public void setContratos(List<Contrato> contratos) {
		this.contratos = contratos;
	}

	/*
	public ContratoDataModel getContratosDataModel() {
		if(contratosDataModel == null){
			contratosDataModel = new ContratoDataModel(getContratos());
		}
		return contratosDataModel;
	}


	public void setContratosDataModel(ContratoDataModel contratosDataModel) {
		this.contratosDataModel = contratosDataModel;
	}*/


	public Contrato[] getContratosSelecionados() {
		return contratosSelecionados;
	}


	public void setContratosSelecionados(Contrato[] contratosSelecionados) {
		this.contratosSelecionados = contratosSelecionados;
	}


	public List<SelectItem> getAnosItens() {
		//mostra ano anterior/ano atual/ano posterior
		if(anosItens == null){
			anosItens = new ArrayList<SelectItem>();
			Integer anoCorrente = Calendar.getInstance().get(Calendar.YEAR);
			Integer anoAnterior = anoCorrente - 1;
			Integer AnoSeguinte = anoCorrente + 1;
			this.anosItens.add(new SelectItem(anoAnterior, String.valueOf(anoAnterior)));//value - label
			this.anosItens.add(new SelectItem(anoCorrente, String.valueOf(anoCorrente)));//value - label
			this.anosItens.add(new SelectItem(AnoSeguinte, String.valueOf(AnoSeguinte)));//value - label
		}
		return anosItens;
	}
	
	public List<SelectItem> getMesesItens() {
		if(mesesItens == null){
			mesesItens = new ArrayList<SelectItem>();
			//this.mesesItens.add(new SelectItem(null, " "));
			for (Mes item : Mes.values())
				this.mesesItens.add(new SelectItem(item,item.getDescricao()));//value - label
		}
		return mesesItens;
	}

	public Mes getMesDeReferenciaSelecionado() {
		return mesDeReferenciaSelecionado;
	}

	public void setMesDeReferenciaSelecionado(Mes mesDeReferenciaSelecionado) {
		this.mesDeReferenciaSelecionado = mesDeReferenciaSelecionado;
	}


	public Integer getAnoDeReferenciaSelecionado() {
		return anoDeReferenciaSelecionado;
	}


	public void setAnoDeReferenciaSelecionado(Integer anoDeReferenciaSelecionado) {
		this.anoDeReferenciaSelecionado = anoDeReferenciaSelecionado;
	}


	public List<Contrato> getContratosFiltrados() {
		return contratosFiltrados;
	}

	public void setContratosFiltrados(List<Contrato> contratosFiltrados) {
		this.contratosFiltrados = contratosFiltrados;
	}



	public List<ContaAReceber> getContasAReceberSelecionadas() {
		
		if(getContratosSelecionados() == null || getContratosSelecionados().length == 0){
			contasAReceberSelecionadas = null;
		}else{
			contasAReceberSelecionadas = new ArrayList<ContaAReceber>();
			for(int i = 0; i < getContratosSelecionados().length; i++){
				contasAReceberSelecionadas.add(new ContaAReceber(getContratosSelecionados()[i], getAnoDeReferenciaSelecionado(), getMesDeReferenciaSelecionado(), getDataDoVencimentoSelecionado()));
			}
		}
		
		return contasAReceberSelecionadas;
	}

/*	public List<ContaAReceber> getContasAReceberCadastradas() {
		if(contasAReceberCadastradas == null){
			contasAReceberCadastradas = new ContaAReceberRN().getContasPendentesDePagamento();
		}
		return contasAReceberCadastradas;
	}*/

	public List<ContaAReceber> getContasPendentesDePagamento() {
		if(contasPendentesDePagamento == null || contasPendentesDePagamento.size() == 0){
			setContasPendentesDePagamento(new ContaAReceberRN().getContasPendentesDePagamento());
		}
		return contasPendentesDePagamento;
	}
	
	public void setContasPendentesDePagamento(List<ContaAReceber> contasPendentesDePagamento){
		this.contasPendentesDePagamento = contasPendentesDePagamento;
	}
	
	
/*	public void setContasAReceberCadastradas(List<ContaAReceber> contasAReceberCadastradas) {
		this.contasAReceberCadastradas = contasAReceberCadastradas;
	}
*/

	public ContaAReceber getContaAReceberSelecionada() {
		return contaAReceberSelecionada;
	}

	public void setContaAReceberSelecionada(ContaAReceber contaAReceberSelecionada) {
		this.contaAReceberSelecionada = contaAReceberSelecionada;
	}


	public Date getDataDoVencimentoSelecionado() {
		return dataDoVencimentoSelecionado;
	}

	public void setDataDoVencimentoSelecionado(Date dataDoVencimentoSelecionado) {
		this.dataDoVencimentoSelecionado = dataDoVencimentoSelecionado;
	}


	public Pagamento getPagamentoContaAReceberSelecionada() {
		return pagamentoContaAReceberSelecionada;
	}

	public void setPagamentoContaAReceberSelecionada(Pagamento pagamentoContaAReceberSelecionada) {
		this.pagamentoContaAReceberSelecionada = pagamentoContaAReceberSelecionada;
	}







	//InnerClass
	/*public class ContratoDataModel extends ListDataModel<Contrato> implements SelectableDataModel<Contrato> { 
				 public ContratoDataModel() {  
		 }  
		  
		 public ContratoDataModel(List<Contrato> contratos) {  
		      super(contratos);  
		 }  
		      
	    @Override  
	    public Contrato getRowData(String rowKey) {  
	        //In a real app, a more efficient way like a query by rowKey should be implemented to deal with huge data  
	          
	        @SuppressWarnings("unchecked")
			List<Contrato> contratos = (List<Contrato>) getWrappedData();  
	          
	        for(Contrato contrato : contratos) {  
	            if(contrato.getId() == Integer.parseInt(rowKey)){  
	                return contrato;  
	            }
	        }  
	          
	        return null;  
	    }  
		  
	    @Override  
	    public Object getRowKey(Contrato contrato) {  
	        return contrato.getId(); 
	    }  
	}*/
	
	
	
	
	
	
	public class PreBoleto implements Serializable{

		private static final long serialVersionUID = -1308140494803970237L;

		private ContaAReceber contaAReceber;
		private Conta contaBancaria;
		private StreamedContent file;
		private boolean boletoFoiGerado = false;
		CarteiraBoleto carteiraBoleto;
		
		private Date dataDoVencimento;
		private BigDecimal valorDoDocumento = new BigDecimal(0.0);
		private BigDecimal percentualJurosMora = new BigDecimal(0.0);
		private BigDecimal valorJurosMora = new BigDecimal(0.0);
		private BigDecimal valorMulta = new BigDecimal(0.0);
		private BigDecimal percentualMulta = new BigDecimal(0.0);
		
		public PreBoleto(){}
		
		public PreBoleto(ContaAReceber contaAReceber){
			this.contaAReceber = contaAReceber;
			
			this.contaBancaria = new BancoRN().getConta(Constante.CONSERVARE_NUMERO_CNPJ,  Constante.CONSERVARE_NUMERO_BANCO_CEF, Constante.CONSERVARE_NUMERO_AGENCIA_CEF, Constante.CONSERVARE_NUMERO_CONTA_CEF);
			this.carteiraBoleto = new BancoRN().getCarteira(contaBancaria, Constante.CONSERVARE_NUMERO_CARTEIRA, Constante.CONSERVARE_MODALIDADE_CARTEIRA);
			this.contaAReceber = getContaAReceberSelecionada();
			this.dataDoVencimento = this.contaAReceber.getDataDeVencimento();
			this.valorDoDocumento = this.contaAReceber.getValorAPagar();
			this.percentualJurosMora = this.carteiraBoleto.getPercentualJurosMora();
			this.percentualMulta = this.carteiraBoleto.getPercentualMulta();
			doValorDocumentoBoletoAlterado();
		}
		

		public void doPercentualMultaAposVencimentoBoletoAlterado(){
			
			recalcularValorMultaAposVencimentoBoletoSelecionado();
			
		}
		
		private void recalcularValorMultaAposVencimentoBoletoSelecionado(){
			setValorMulta(new BoletoEmitidoRN().calcularValorMultaAposVencimento(this.valorDoDocumento, this.carteiraBoleto.getPercentualMulta()));
		}

		public void doPercentualJurosMoraBoletoAlterado(){
			
			recalcularValorJurosDeMoraNoBoletoSelecionado();
			
		}
		
		private void recalcularValorJurosDeMoraNoBoletoSelecionado(){
			
			setValorJurosMora(new BoletoEmitidoRN().calcularValorJurosMora(this.valorDoDocumento, this.carteiraBoleto.getPercentualJurosMora()));
			
		}
		
		public void doValorDocumentoBoletoAlterado(){
			
			recalcularValorJurosDeMoraNoBoletoSelecionado();
			recalcularValorMultaAposVencimentoBoletoSelecionado();
			
		}
		
		
		public BigDecimal getPercentualJurosMora() {
			
			if(this.percentualJurosMora == null){
				this.percentualJurosMora = new BigDecimal(0.0);
			} 
			
			return percentualJurosMora;
		}

		public void setPercentualJurosMora(BigDecimal percentualJurosMora) {
		
				this.percentualJurosMora = percentualJurosMora;
			
		}

		
		public BigDecimal getPercentualMulta() {
			
			if(this.percentualMulta == null){
				this.percentualMulta = new BigDecimal(0.0);
			}
			
			return percentualMulta;
		}

		public void setPercentualMulta(BigDecimal percentualMulta) {
			this.percentualMulta = percentualMulta;
		}

		public Date getDataDoVencimento() {
			return dataDoVencimento;
		}


		public void setDataDoVencimento(Date dataDoVencimento) {
			this.dataDoVencimento = dataDoVencimento;
		}


		public BigDecimal getValorDoDocumento() {
			return valorDoDocumento;
		}


		public void setValorDoDocumento(BigDecimal valorDoDocumento) {
			this.valorDoDocumento = valorDoDocumento;
		}


		public BigDecimal getValorJurosMora() {
			return valorJurosMora;
		}


		public void setValorJurosMora(BigDecimal valorJurosMora) {
			this.valorJurosMora = valorJurosMora;
		}


		public BigDecimal getValorMulta() {
			return valorMulta;
		}


		public void setValorMulta(BigDecimal valorMulta) {
			this.valorMulta = valorMulta;
		}


		
		public CarteiraBoleto getCarteiraBoleto() {
			return carteiraBoleto;
		}

		public void setCarteiraBoleto(CarteiraBoleto carteiraBoleto) {
			this.carteiraBoleto = carteiraBoleto;
		}
		
		

		public Conta getContaBancaria() {
			return contaBancaria;
		}

		public void setContaBancaria(Conta contaBancaria) {
			this.contaBancaria = contaBancaria;
		}

		/*public StreamedContent getFile() {
			
			BoletoViewer boletoViewer = gerarBoleto();
			InputStream stream = new ByteArrayInputStream(boletoViewer.getPdfAsStream().toByteArray());
			file = new DefaultStreamedContent(stream, "application/pdf", "boleto.pdf"); 
			
			boletoFoiGerado = true;
			
			return file;
		}*/
		
		public StreamedContent getFile() {
			
			InputStream stream = gerarBoleto();
			file = new DefaultStreamedContent(stream, "application/pdf", "boleto.pdf"); 
			
			return file;
		}
		
		public InputStream gerarBoleto(){
			
			
			GeradorBoletoService boletoService = new GeradorBoletoService(contaAReceber, contaBancaria, carteiraBoleto, new Date(), dataDoVencimento, valorDoDocumento, valorJurosMora, valorMulta);
			InputStream stream = null;
			
			try {
				stream = boletoService.executa();
			}catch (Exception e) {
				e.printStackTrace();
			}
			
			
		/*	
			InfoBoletoBuilder infoBoletoBuilder = new InfoBoletoBuilder();
			infoBoletoBuilder.buildContaAReceber(contaAReceber);
			infoBoletoBuilder.buildContaBancaria(contaBancaria);
			infoBoletoBuilder.buildDataDoDocumento(new Date());
			infoBoletoBuilder.buildDataDoVencimento(dataDoVencimento);
			infoBoletoBuilder.buildNumeroDoDocumento(InfoBoletoRN.gerarSequencialBoleto(carteiraBoleto));
			infoBoletoBuilder.buildValorDoDocumento(valorDoDocumento);
			infoBoletoBuilder.buildValorJurosMora(valorJurosMora);
			infoBoletoBuilder.buildValorMulta(valorMulta);
			infoBoletoBuilder.buildPagador(contaAReceber.getContrato().getResponsavelLocalPrestacaoServico());
			
			InfoBoleto infoBoleto = infoBoletoBuilder.getInfoBoleto();
			
			
			
			BoletoViewer boletoViewer = null;
			GeradorBoleto geradorBoleto = null;
			
			try {
				
				geradorBoleto = GeradorBoletoFactory.criarGeradorBoleto(infoBoleto, carteiraBoleto);
				
				boletoViewer = geradorBoleto.executar();
				
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			infoBoleto.setNossoNumero(geradorBoleto.getNossoNumeroParaExibicao());
			
			new InfoBoletoRN().salvar(infoBoleto);
			*/
			return stream;
			
		}


		public boolean isBoletoFoiGerado() {
			return boletoFoiGerado;
		}
		
		

		
	}
	
	
}
